﻿using CinemaMaestro.ViewModels;
using CinemaMaestro.WindowsApplication.EndPoints;
using MetroFramework;
using MetroFramework.Controls;
using MetroFramework.Forms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CinemaMaestro.WindowsApplication.Sale
{
    public partial class SalesForm : MetroForm
    {
        private ReservationEndPoints reservationEndPoints;
        private SaleEndPoints saleEndPoints;
        private CinemaEndPoints cinemaEndPoints;
        private ScreeningEndPoints screeningEndPoints;
        private MetroTile[] seats;

        private double Total;
        private int seatCount;
        private int selectedSeatCount;
        private int clickedSeatCount;

        public SalesForm(HttpClient client)
        {
            this.reservationEndPoints = new ReservationEndPoints(client);
            this.saleEndPoints = new SaleEndPoints(client);
            this.cinemaEndPoints = new CinemaEndPoints(client);
            this.screeningEndPoints = new ScreeningEndPoints(client);
            this.seats = new MetroTile[100];

            InitializeComponent();

            
        }

        private void SalesFormToInitialState()
        {
            cinemaComboBox.SelectedIndex = -1;
            screeningsComboBox.Enabled = false;
            screeningsComboBox.SelectedIndex = -1;
            reservationsComboBox.Enabled = false;
            reservationsComboBox.SelectedIndex = -1;
            availableTicketLabel.Text = String.Empty;
            totalLabel.Text = String.Empty;
            priceLabel.Text = "0.00";
            discountPriceLabel.Text = "0.00";
            ticketUpDown.Value = 0;
            discountTicketUpDown.Value = 0;
            selectedSeatCount = 0;
            clickedSeatCount = 0;
            DeSelectAllSeats();
            HideAllSeats();
        }

        private async void PopulateCinemaComboBox()
        {
            cinemaComboBox.Items.Clear();
            try
            {
                var cinemas = await cinemaEndPoints.GetAllCinemasAsync();
                foreach (var cinema in cinemas)
                {
                    cinemaComboBox.Items.Add(cinema);
                }
            }
            catch
            {
                MetroMessageBox.Show(this, "Cannot retrieve cinemas!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }
        }

        private void cinemaComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cinemaComboBox.SelectedIndex > -1)
            {
                screeningsComboBox.Enabled = true;
                screeningsComboBox.SelectedIndex = -1;
                var selectedId = ((CinemaViewModel)cinemaComboBox.SelectedItem).Id;
                PopulateScreeningsComboBox(selectedId);
                HideAllSeats();
            }
            else
            {
                screeningsComboBox.Enabled = false;
                screeningsComboBox.SelectedIndex = -1;
                priceLabel.Text = "0";
                discountPriceLabel.Text = "0";
                availableTicketLabel.Text = String.Empty;
                totalLabel.Text = String.Empty;
                HideAllSeats();
            }
        }

        private async void PopulateScreeningsComboBox(int selectedId)
        {
            screeningsComboBox.Items.Clear();
            try
            {
                var screenings = await screeningEndPoints.GetTodaysScreeningsForCinema(selectedId);
                foreach (var screening in screenings)
                {
                    screeningsComboBox.Items.Add(screening);
                }
            }
            catch
            {
                MetroMessageBox.Show(this, "Cannot retrieve screenings!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }
        }

        private void screeningsComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (screeningsComboBox.SelectedIndex > -1)
            {
                reservationsComboBox.Enabled = true;
                reservationsComboBox.SelectedIndex = -1;
                var selected = ((ScreeningViewModel)screeningsComboBox.SelectedItem);
                PopulateReservationsComboBox(selected.Id);
                priceLabel.Text = selected.Price.ToString();
                discountPriceLabel.Text = selected.DiscountedPrice.ToString();
                ticketUpDown.Value = 0;
                discountTicketUpDown.Value = 0;
                ShowAvailabeSeatCount(selected.Id);
                DeSelectAllSeats();
                ShowOccupiedSeats(selected.Id);
                ShowRoomLayout(selected.Room);
            }
            else
            {
                reservationsComboBox.Enabled = false;
                reservationsComboBox.SelectedIndex = -1;
                priceLabel.Text = "0";
                discountPriceLabel.Text = "0";
                availableTicketLabel.Text = String.Empty;
                totalLabel.Text = String.Empty;
            }
        }

        private async void PopulateReservationsComboBox(int selectedId)
        {
            reservationsComboBox.Items.Clear();
            try
            {
                var reservations = await reservationEndPoints.GetReservationsForScreening(selectedId);
                foreach (var reservation in reservations)
                {
                    reservationsComboBox.Items.Add(reservation);
                }
            }
            catch
            {
                MetroMessageBox.Show(this, "Cannot retrieve reservations!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }
        }

        private async void reservationsComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (reservationsComboBox.SelectedIndex > -1)
            {
                var selectedScreening = ((ScreeningViewModel)screeningsComboBox.SelectedItem);
                DeSelectAllSeats();
                await ShowOccupiedSeats(selectedScreening.Id);
                var selected = ((ReservationViewModel)reservationsComboBox.SelectedItem);
                ticketUpDown.Value = selected.TicketNr;
                discountTicketUpDown.Value = selected.DiscountTicketNr;
                selectedSeatCount = selected.TicketNr + selected.DiscountTicketNr;                
                MakeCurrentReservedSeatsSelectable(selected);
            }
        }

        private async void ShowAvailabeSeatCount(int screeningId)
        {
            try
            {
                var availableSeatCount = await saleEndPoints.GetAvailableSeatCount(screeningId);
                availableTicketLabel.Text = availableSeatCount.ToString();
                seatCount = availableSeatCount;
            }
            catch
            {
                MetroMessageBox.Show(this, "Cannot retrieve available seat count!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }
        }

        private bool ValidateSale()
        {
            if (ticketUpDown.Value == 0 && discountTicketUpDown.Value == 0)
            {
                MetroMessageBox.Show(this, "Cannot sell zero tickets!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
                return false;
            }
            if (screeningsComboBox.SelectedIndex == -1)
            {
                MetroMessageBox.Show(this, "Please select a screening!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
                return false;
            }
            if (ticketUpDown.Value + discountTicketUpDown.Value > clickedSeatCount)
            {
                MetroMessageBox.Show(this, "More seat count specified than selected!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
                return false;
            }      
            return true;
        }

        private async void sellButton_Click(object sender, EventArgs e)
        {
            if (ValidateSale())
            {
                try
                {
                    var selectedScreening = (ScreeningViewModel)screeningsComboBox.SelectedItem;

                    var sale = new SaleViewModel
                    {
                        TicketNr = Convert.ToInt32(ticketUpDown.Value),
                        DiscountTicketNr = Convert.ToInt32(discountTicketUpDown.Value),
                        Total = Total,
                        Seats = GetSelectedSeatPositions(),
                        Screening = selectedScreening
                    };

                    var reservationId = 0;
                    if (reservationsComboBox.SelectedIndex != -1)
                    {
                        ReservationViewModel selectedReservation = (ReservationViewModel)reservationsComboBox.SelectedItem;
                        reservationId = selectedReservation.Id;
                    }

                    var success = await saleEndPoints.CreateSaleAsync(sale, reservationId);
                    if (success)
                    {
                        MetroMessageBox.Show(this, "Tickest succesfully sold!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Information);
                        SalesFormToInitialState();
                    }
                    else
                    {
                        MetroMessageBox.Show(this, "Some selected seats were already taken!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
                        ShowAvailabeSeatCount(selectedScreening.Id);
                        DeSelectAllSeats();
                        ShowOccupiedSeats(selectedScreening.Id);
                    }   
                }
                catch
                {
                    MetroMessageBox.Show(this, "Cannot sell tickets! Something went wrong!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
                }
            }
        }

        private void ticketUpDown_ValueChanged(object sender, EventArgs e)
        {
            if (screeningsComboBox.SelectedIndex != -1)
            {
                var selectedScreening = (ScreeningViewModel)screeningsComboBox.SelectedItem;
                Total = Convert.ToDouble(ticketUpDown.Value) * selectedScreening.Price +
                    Convert.ToDouble(discountTicketUpDown.Value) * selectedScreening.DiscountedPrice;
                selectedSeatCount = Convert.ToInt32(ticketUpDown.Value + discountTicketUpDown.Value);
                totalLabel.Text = Total.ToString();
            }
        }

        private void discountTicketUpDown_ValueChanged(object sender, EventArgs e)
        {
            if (screeningsComboBox.SelectedIndex != -1)
            {
                var selectedScreening = (ScreeningViewModel)screeningsComboBox.SelectedItem;
                Total = Convert.ToDouble(ticketUpDown.Value) * selectedScreening.Price +
                    Convert.ToDouble(discountTicketUpDown.Value) * selectedScreening.DiscountedPrice;
                selectedSeatCount = Convert.ToInt32(ticketUpDown.Value + discountTicketUpDown.Value);
                totalLabel.Text = Total.ToString();
            }
        }

        private void SalesForm_Load(object sender, EventArgs e)
        {
            for (int y = 0; y < 10; y++)
            {
                for (int x = 0; x < 10; x++)
                {
                    MetroTile tile = new MetroTile();
                    tile.Left = 480 + x * 35;
                    tile.Top = 50 + y * 35;
                    tile.Width = 30;
                    tile.Height = 30;
                    tile.UseCustomBackColor = true;
                    tile.BackColor = Color.LightGreen;
                    tile.Name = "Seat:" + y + "-" + x;
                    tile.Click += (sendr, args) => ChangeSelected(tile);
                    this.seats[y * 10 + x] = tile;
                    this.Controls.Add(tile);
                }
            }
            SalesFormToInitialState();
            PopulateCinemaComboBox();
        }

        private void DeSelectAllSeats()
        {
            for (int i = 0; i < seats.Length; i++)
            {
                seats[i].BackColor = Color.LightGreen;
            }
        }

        private void HideAllSeats()
        {
            for (int i = 0; i < seats.Length; i++)
            {
                seats[i].Hide();
            }
        }

        private void ShowRoomLayout(RoomViewModel room)
        {
            string[] rows = room.Seats.Split(',');
            for (int i = 0; i < rows.Length; i++)
            {
                for (int j = 0; j < rows[i].Length; j++)
                {
                    if (rows[i][j] == 'a')
                    {
                        seats[i * 10 + j].Show();
                    }
                    else
                    {
                        seats[i * 10 + j].Hide();
                    }
                }
            }
        }

        private void ChangeSelected(MetroTile tile)
        {
            if (tile.BackColor == Color.LightGreen)
            {
                if (clickedSeatCount < selectedSeatCount)
                {
                    tile.BackColor = Color.Orange;
                    clickedSeatCount++;
                }     
            }
            else if (tile.BackColor == Color.Orange)
            {
                tile.BackColor = Color.LightGreen;
                clickedSeatCount--;
            }
        }

        private async Task ShowOccupiedSeats(int screeningId)
        {
            try
            {
                var occupiedSeats = await saleEndPoints.GetOccupiedSeats(screeningId);
                if (occupiedSeats != String.Empty)
                {
                    string[] occupied = occupiedSeats.Split(',');
                    for (int i = 0; i < occupied.Length; i++)
                    {
                        string[] positions = occupied[i].Split('_');
                        var row = Convert.ToInt32(positions[0]) - 1;
                        var col = Convert.ToInt32(positions[1]) - 1;
                        seats[row * 10 + col].BackColor = Color.LightGray;
                    }
                }               
            }
            catch
            {
                MetroMessageBox.Show(this, "Cannot retrieve occupied seats!", String.Empty, MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }
        }

        private void MakeCurrentReservedSeatsSelectable(ReservationViewModel reservation)
        {
            clickedSeatCount = 0;
            string[] occupied = reservation.ReservedSeats.Split(',');
            for (int i = 0; i < occupied.Length; i++)
            {
                string[] positions = occupied[i].Split('_');
                var row = Convert.ToInt32(positions[0]) - 1;
                var col = Convert.ToInt32(positions[1]) - 1;
                seats[row * 10 + col].BackColor = Color.Orange;
                clickedSeatCount++;
            }
        }

        private string GetSelectedSeatPositions()
        {
            string positions = String.Empty;
            for (int y = 0; y < 10; y++)
            {
                for (int x = 0; x < 10; x++)
                {
                    var currentSeat = seats[y * 10 + x];
                    if (currentSeat.BackColor == Color.Orange)
                    {
                        positions += (y + 1);
                        positions += "_";
                        positions += (x + 1);
                        positions += ",";
                    }
                }
            }
            positions = positions.Substring(0, positions.Length - 1);
            return positions;
        }

    }
}
